<?php
/**
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT		: Rubik Ultimate Framework
 * @version 	: 1.1
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 * 
 * Created on	:  Jul 9, 2008
 * 
 */

// no direct access
defined ( '_FW_EXEC' ) or die ( 'Restricted access' );

RCoreImporter::cls( "html.BasePagination" );
RCoreImporter::cls( "html.AbstractFieldsControl" );

class TableControl extends AbstractFieldsControl {
	
	var $_arrayRequest;
	var $_dtoName;
	
	/**
	 * dto
	 *
	 * @var AbstratctDTO
	 */
	var $_where;
	
	/**
	 * Key field
	 *
	 * @var RubikDBField
	 */
	var $_keyField;
	
	var $_orderby;
	var $_defaultOrderBy;
	var $_sort;
	var $_page;
	
	var $_showFilter = true;
	var $_showCheckbox = true;
	
	/**
	 * Database
	 *
	 * @var Database
	 */
	var $_db;
	
	// $arrayViewField = array("fieldname"=>"rule_link", "field_name"=>""); 
	function __construct($dtoName, $arrayViewField, &$arrayRequest, $name = "tblAdminControl", $where = '', $orderBy ='', $db = null) {
		parent::__construct ( new $dtoName(), $arrayViewField, null, $name );
		if (empty ( $db )) {
			$this->_db = &SysDatabase::getInstance ();
		} else {
			$this->_db = &$db;
		}
		$this->_dtoName = $dtoName;
		$this->_where = $where;
		$this->_arrayRequest = &$arrayRequest;
		$this->_defaultOrderBy = $orderBy;
		$this->_orderby = "x_{$name}_orderby";
		$this->_sort = "x_{$name}_sort";
		$this->_page = "x_{$name}_page";
	}
	
	/**
	 * Set the field information for a special field
	 *
	 * @param string $fieldName
	 * @param int/string $widthValue
	 */
	function setWidthHtmlInfo($fieldName, $widthValue) {
		$field = &$this->_arrayFields[$fieldName];
		$field->width = $widthValue;
	}
	
	/**
	 * Set the check box will be show or not when the table is generated
	 *
	 * @param boolean $show
	 */
	function setShowCheckBox($show) {
		$this->_showCheckbox = $show;
	}
	
	/**
	 * Get data result
	 *
	 * @param sql string $orderBy
	 * @param number $recordPerPage
	 * @param number $indexPage
	 * @param string $prefix
	 * @return SelectResult
	 */
	function _getDataResult($orderBy = '', $recordPerPage = null, $indexPage = 1, $prefix = "#__") {
		$where = $this->createFilterWhere();
		if (!empty($this->_where)) {
			$where .= empty($where) ? $this->_where :  " AND ({$this->_where})";
		}
		
		$dto = new $this->_dtoName ( $where, $orderBy );
		$this->_dto = $dto;
		$db = $this->_db;
		$result = $db->getSelectResult ( $dto, $recordPerPage, $indexPage, $prefix );
		if ($result->isEmptyRecord ()) {
			$res = SysRequest::getResource ();
			$res->setExtend ( $this->_page, 1 );
			$result = $db->getSelectResult ( $dto, $recordPerPage, 1, $prefix );
		}
		return $result;
	}
	
	/**
	 * Create the where clause for the filter
	 *
	 * @return string
	 */
	function createFilterWhere() {
		$whereDto = new $this->_dtoName($this->_where);
		$whereDto->resetToNull();
		$ctrlName = $this->_inputName;
		$whereDto->bind($this->_arrayRequest, array(), "x_{$ctrlName}_filter_");
		
		$whereDto->setEmptyToNull();
		$where = RubikDBFactory::createWhereClause($whereDto, "AND", true, 'LIKE', '%', '%');
		return $where;
	}

	/**
	 * Set the table control for showing filter or not.
	 *
	 * @param boolean $show
	 */
	function setShowFilter($show) {
		$this->_showFilter = $show;
	}
	
	/**
	 * Create HTML table
	 *
	 * @param number $recordPerPage
	 * @param string $attributes
	 * @param string $prefix
	 */
	function createHtmlTable($recordPerPage = 10, $attributes = 'width="100%" cellspacing="1" cellpadding="0" border="0" class="tblAdminDetail"', $prefix = "#__") {
		$indexPage = $this->_arrayRequest [$this->_page];
		if (empty ( $indexPage ))
			$indexPage = 1;
		
		$orderBy = '';
		if(!empty($this->_defaultOrderBy)) 
			$orderBy = 'ORDER BY '.$this->_defaultOrderBy;
		if ($this->_arrayRequest [$this->_orderby])
			$orderBy = 'ORDER BY ' . $this->_arrayRequest [$this->_orderby] . ' ' . $this->_arrayRequest [$this->_sort];
		$res = SysRequest::cloneResource();
		
		$res->removeExtendWithoutPrefix ();
		$res->removeExtend($this->_page);
		$pagerLink = $res->getLink ();
		if (strpos($pagerLink, '?') === false) {
			 $pagerLink .= "?{$this->_page}";
		}
		else {
			 $pagerLink .= "&{$this->_page}";
		}
		
		$result = $this->_getDataResult ( $orderBy, $recordPerPage, $indexPage, $prefix );
		
		$totalItems = $result->getTotalRecords ();
		

		$output = '';
		$output .= "<table $attributes>";
		$output .= $this->_getFilter ( $this->_dto );
		$output .= $this->_getHeader ( $this->_dto );
		$output .= $this->getData ( $result );
		$output .= '</table>';
		$output .= $this->getPager ( $totalItems, $recordPerPage, $indexPage, $pagerLink );
		return $output;
	}
	
	/**
	 * Print the HTML table code
	 *
	 * @param number $recordPerPage
	 * @param string $attributes
	 * @param string $prefix
	 */
	function printHtmlTable($recordPerPage = 10, $attributes = 'width="100%" cellspacing="1" cellpadding="0" border="0" class="tblAdminDetail"', $prefix = "#__") {
		echo $this->createHtmlTable ( $recordPerPage, $attributes, $prefix );
	}
	
	/**
	 * Build Header Data
	 *
	 * @param DTO $dto
	 * @return 
	 */
	function _getHeader($dto) {
		$dbInfo = RubikDBFactory::getDBInfo ( $dto );
		$checkBox = $this->getCheckBoxAll ();
		
		$output = '<tr>';
		$output .= "<th width=\"20\" align=\"center\" title=\"Index\">#</th>";
		if ($this->_showCheckbox) {
		$output .= "<th width=\"20\" align=\"center\">$checkBox</th>";
		}
		else {
			$output .= "<th></th>";
		}
		foreach ( $this->_arrayFields as $key => $value ) {
			$fieldInfo = $dbInfo->getDbField ( $key );
			$align = $this->createAlign($fieldInfo);
			$langKey = $this->getLabel( $key );
			if (empty($fieldInfo)) {
				$output .= "<th".$align.">".$langKey."</th>";
				continue;
			}
			$fieldName = $fieldInfo->getNameWithAlias ( $dbInfo );
			
			$resource = SysRequest::cloneResource ();
			
			$resource->setExtend ( $this->_orderby, $fieldName );
			$sort = 'desc';
			if ($this->_arrayRequest [$this->_orderby] == $fieldName) {
				if (! empty ( $this->_arrayRequest [$this->_sort] ) && $this->_arrayRequest [$this->_sort] == 'desc') {
					$sort = 'asc';
				}
			}
			
			$resource->setExtend ( $this->_sort, $sort );
			
			$link = $resource->getLink ();
			$icon = $this->getSortIcon ( $this->_arrayRequest [$this->_sort], $key );
			
			$width = '';
			if ($value->width) {
				$width = "width=\"{$value->width}\"";
			}
			$output .= "<th $width $align><a href=\"$link\">$langKey $icon</a></th>";
		}
		$output .= $this->addMoreHtmlHeaderField();
		
		$output .= '</tr>';
		return $output;
	}
	
	/**
	 * Build Filter Data
	 *
	 * @param DTO $dto
	 * @return 
	 */
	function _getFilter($dto) {
		if (!$this->_showFilter) {
			return '';
		}
		$dbInfo = RubikDBFactory::getDBInfo ( $dto );
		
		$ctrlName = $this->_inputName;
		$output = "<tr id=\"x_{$ctrlName}_filter\" class=\"admin_tbl_filter\">";
		$output .= "<td width=\"80\" colspan=\"2\" align=\"center\">
						<input type=\"submit\" value=\"Filter\" class=\"tblBtn\" />
						<input type=\"button\" value=\"Reset\" class=\"tblBtn\" onclick=\"return reset_{$ctrlName}Values();\" />
						<script type=\"text/javascript\">
							function reset_{$ctrlName}Values() {
								// reset all values
								\$('#x_{$ctrlName}_filter input').val('');
								\$('#x_{$ctrlName}_filter select').val('');
								systemForm.submit();
							}
						</script>
					</td>";
		foreach ( $this->_arrayFields as $key => $value ) {
			$fieldInfo = $dbInfo->getDbField ( $key );
			$align = $this->createAlign($fieldInfo);
			$html = $this->createHtmlFilterField($fieldInfo, $ctrlName, $key, $value);
			$output .= "<td $align>{$html}</td>";
		}
		$output .= $this->addMoreHtmlFilterField();
		$output .= '</tr>';
		return $output;
	}
	
	/**
	 * Build data from recordSet
	 *
	 * @param SelectResult $result
	 * @return 
	 */
	function getData($result) {
		$recordSet = $result->recordSet;
		$number = 1;
		$number = ($result->getIndexPage () - 1) * $result->getRecordPerPage() + 1;

		$this->_keyField = $this->getKeyFieldName ( $this->_dto );
		$keyField = $this->_keyField;
		
		$dbInfo = RubikDBFactory::getDBInfo($this->_dto);

		$output = '';
		
		foreach ( $recordSet as $recordValue ) {
			if ($number % 2 == 0) {
				$cls = "even";
			}
			else {
				$cls = "odd";
			}
			$output .= "<tr class=\"{$cls}\">";
			$keyValue = $recordValue->$keyField;
			if ($this->_showCheckbox) {
			$checkBox = $this->getCheckBox ( "cid[]", $keyValue );
			}
			$output .= "<td align=\"center\">$number</td>";
			$output .= "<td align=\"center\">$checkBox</td>";
			foreach ( $this->_arrayFields as $key => $fieldValue ) {
				$fieldInfo = $dbInfo->getDbField ( $key );
				$data = $this->createHtmlDataField($recordValue, $key, $fieldValue, $keyValue, $fieldInfo);
				$align = $this->createAlign($fieldInfo);
				$output .= "<td $align>$data</td>";
			}
			$this->addMoreHtmlDataField($keyValue);
			$output .= "</tr>";
			$number ++;
		}
		return $output;
	}
	
	/**
	 * Build Pagination for table
	 *
	 * @param Number $totalItems
	 * @param Number $itemsPerPage
	 * @param Number $index
	 * @param String $link
	 * @return show pagination
	 */
	function getPager($totalItems, $itemsPerPage, $index, $link) {
		if ($totalItems) {
			$pager = SysTemplate::getPaginationInstance ( $totalItems, $itemsPerPage, $link );
			
			$start = ($index-1) * $itemsPerPage + 1;
			$end = $index * $itemsPerPage;
			$end = ($end > $totalItems) ? $totalItems : $end;
			
			return '<div class="admin_tbl_pager"><span style="float:left;" class="message">'."Records: {$start}-{$end} of {$totalItems}</span>". $pager->renderPager ( $index ) ."</div>";
		} 
		else {
			return '<div class="admin_tbl_pager"><span class="message">'. $this->getLabel( "There isn't any record!" ) ."</span></div>";
		}
	}
	
	/**
	 * Get Sort Icon
	 *
	 * @param String $sortType
	 * @param String $key
	 * @return HTML Image Tag
	 */
	function getSortIcon($sortType = '', $key = '') {
		$currentKey = $this->_arrayRequest [$this->_orderby];
		if (! empty ( $sortType ) && $key == $currentKey) {
			$imagePath = SYS_CUR_TMPL_URL;
			if ($sortType == 'asc') {
				$image = '<img src="' . $imagePath . 'images/arrow-asc.png' . '" />';
			} else if ($sortType == 'desc') {
				$image = '<img src="' . $imagePath . 'images/arrow-desc.png' . '" />';
			}
			return $image;
		}
		return '';
	}
	
	/**
	 * Create Link for Items data
	 *
	 * @param string $data
	 * @param Number $key
	 * @param String|Object $rule
	 * @return HTML href tag
	 */
	function createItemsLink($data, $key, $rule = '', $fieldInfo) {
		$dbKeyField = $this->_keyField;
		if ($rule->_isColumnInfo) {
			if ($rule->_columnType == HTML_INFO_PICTURE_TYPE || $rule->_columnType == HTML_INFO_PICTURE_FORM || $rule->_columnType == HTML_INFO_FLASH_TYPE) {
				$html = $rule->generateHTML ( $data );
				return $html;
			} else {
				$rule = '';
			}
		}
		
		if ($rule == '') {
			return $data;
		}
		
		if ($rule->isHtmlFieldInfo) {
			$rule->setValue($data);
			return $rule->getPreviewDataHtml($fieldInfo->dataType, $key, $extAttributes = '', $borderTag = '');
		}
		
		if (is_object ( $rule )) {
			$link = $rule->getLink () . "&$dbKeyField=" . $key;
		} else if (strpos ( $rule, '$key' ) !== false) {
			eval ( "\$link = \"{$rule}\";" );
		} else {
			$link = $rule . $key;
		}
		return "<a href=\"$link\">$data</a>";
	}
	
	/**
	 * Get Field Name of PrimaryKey
	 *
	 * @param DTO $dto
	 * @return String
	 */
	function getKeyFieldName($dto) {
		$dbInfo = RubikDBFactory::getDBInfo ( $dto );
		$dbField = $dbInfo->getKeyField ();
		$dbKeyField = $dbField->fieldName;
		return $dbKeyField;
	}
	
	/**
	 * Check Field is Boolean or Not
	 *
	 * @param RubikDBInfo $dbInfo
	 * @param string $name
	 * @return true|false
	 */
	function typeOfFieldNameisBoolean($dbInfo, $name){
		$dbField = $dbInfo->getDbField ( $name );
		if ($dbField) {
			return $dbField->isBoolean ();
		}
		return false;
	}
	
	/**
	 * Check Field is Boolean or Not
	 *
	 * @param RubikDBInfo $dbInfo
	 * @param string $name
	 * @return true|false
	 */
	function typeOfFieldNameisDate($dbInfo, $name){
		$dbField = $dbInfo->getDbField($name);
		if($dbField){
			return $dbField->isDate();
		}
		return false;
	}
	
	/**
	 * Build CheckBox
	 *
	 * @param String $name
	 * @param Number $value
	 * @return HTML Checkbox Tag
	 */
	function getCheckBox($name, $value) {
		return "<input type=\"checkbox\" id=\"cid\" value=\"$value\" name=\"$name\"/>";
	}
	
	/**
	 * Build Checkbox to check All
	 *
	 * @return HTML checkbox tag
	 */
	function getCheckBoxAll() {
		return "<input title=\"Click here for toggle all check boxes\" type=\"checkbox\" value=\"\" id=\"checkAll\" name=\"\"/>";
	}
	
	/////////////////////////////////////////////////////////////////////////////////////////////////
	//	FUNCTIONS FOR OVERRIDE
	/////////////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Add more filters
	 * FOR OVERRIDE this function is created for override perpose
	 * 
	 * Ex: <th>Edit</th> <th>Preview</th>
	 */
	function addMoreHtmlHeaderField() {
		return;
	}
	
	/**
	 * Add more filters
	 * FOR OVERRIDE this function is created for override perpose
	 * 
	 * Ex: <td><a href="#">Edit</a></td> <td><a href="#">Preview</a></td>
	 * 
	 * @param mixe $keyValue the key value of current row
	 */
	function addMoreHtmlDataField($keyValue) {
		return;
	}
	
	/**
	 * Add more filters
	 * FOR OVERRIDE this function is created for override perpose
	 * 
	 * Ex: <td><input name="a"/></td> <td><input name="b" /></td>
	 */
	function addMoreHtmlFilterField() {
		return;
	}
	
	/**
	 * Create the filter input HTML for a DB Field
	 * CAUTION: this function could be override by the sub class 
	 * 
	 * ex: <a href="edit">Edit</a>
	 *
	 * @param RubikDBInfo $dbInfo
	 * @return string
	 */
	function createHtmlDataField($record, $fieldName, $formatLink, $keyValue, $fieldInfo) {
		if (!array_key_exists($fieldName, $record)) {
			return $this->createItemsLink($this->getLabel($fieldName),$keyValue,$formatLink, $fieldInfo);
		}
		
		$fieldData = $record->$fieldName;
			
		return $this->createItemsLink($fieldData,$keyValue,$formatLink, $fieldInfo);
	}
	
	/**
	 * Create the filter input HTML for a DB Field
	 * CAUTION: this function could be override by the sub class 
	 * 
	 * ex: <input name="test" id="test" />
	 *
	 * @param RubikDBField $fieldInfo
	 * @param string $ctrlName
	 * @param string $fieldName
	 * @return string
	 */
	function createHtmlFilterField($fieldInfo, $ctrlName, $fieldName, $value) {
		if (empty($fieldInfo)) {
			return " ";
		}
		$val = $this->_arrayRequest["x_{$ctrlName}_filter_$fieldName"];
		$label = $this->getLabel($fieldName);
		if ($value->_isColumnInfo) {
			if ($value->_columnType != HTML_INFO_PICTURE_TYPE && $value->_columnType != HTML_INFO_FLASH_TYPE) {
				$value->setAttribute ( "title=\"Filter input for '$label'\" name=\"x_{$ctrlName}_filter_$fieldName\" onchange=\"javascript:systemForm.submit();\" name=\"x_{$ctrlName}_filter_$fieldName\" id=\"x_{$ctrlName}_filter_$fieldName\"" );
				$value->setPrefixToName("x_{$ctrlName}_filter_");
				$inputHtml = $value->generateHTML ( $val );
			}
		}
		else if ($value->isHtmlFieldInfo) {
			if ($value->shouldCreateFilter()) {
				$value->setNamePrefix("x_{$ctrlName}_filter_");
				$value->setValue($this->_arrayRequest);
				$inputHtml = $value->getHtmlFilterData($fieldInfo->dataType, "title=\"Filter input for '$label'\"");
			}
		}
		else {
			$inputHtml = "<input title=\"Filter input for '$label'\" name=\"x_{$ctrlName}_filter_$fieldName\" style=\"width:95%; min-width: 20px;\" id=\"x_{$ctrlName}_filter_$fieldName\" value=\"$val\" />";
		}

		return $inputHtml;
	}
	
	/**
	 * Create align for field
	 *
	 * @param RubikDBField $fieldInfo
	 */
	function createAlign($fieldInfo) {
		if (!$fieldInfo) {
			return;
		}
		$align = '';
		if($fieldInfo->isString()) {
			$align = "align=\"left\"";
		} else if ($fieldInfo->isNumeric()) {
			$align = "align=\"right\"";
		} else {
			$align = "align=\"center\"";
		}
		return $align;
	}
	
}

?>
